/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2022-03-29     98409       the first version
 */

#include <stdio.h>
#include <stdint.h>
#include "n32g45x.h"
#include "rtdevice.h"
#include "my_pvd.h"


extern uint16_t ctx_register[2100];

/** @addtogroup PWR_PVD
 * @{
 */

/**
 * @brief  Configures EXTI Lines.
 */
void EXTI_Configuration(void)
{
    EXTI_InitType EXTI_InitStructure;
    /* Configure EXTI Line16(PVD Output) to generate an interrupt on rising and
       falling edges */
    EXTI_ClrITPendBit(EXTI_LINE16);
    EXTI_InitStructure.EXTI_Line    = EXTI_LINE16;
    EXTI_InitStructure.EXTI_Mode    = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_InitPeripheral(&EXTI_InitStructure);
}

/**
 * @brief  Configures NVIC and Vector Table base location.
 */
void NVIC_Configuration(void)
{
    NVIC_InitType NVIC_InitStructure;
    /* Configure one bit for preemption priority */
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
    /* Enable the PVD Interrupt */
    NVIC_InitStructure.NVIC_IRQChannel                   = PVD_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

static void write_params_flash(uint32_t addr)
{
    FLASH_Unlock();

    FLASH_EraseOnePage(addr);

    if(addr == FLASH_WRITE_CMD_ADDR)
    {
        for(int i=0;i<20;i++)
        {
            uint32_t temp = (uint32_t)ctx_register[2020+i*2]*0x10000 + ctx_register[2021+i*2];
            FLASH_ProgramWord(addr + 4*i, temp);  //0x08010106
            rt_kprintf("%d:%d\r\n", i, temp);
        }
    }
    else if(addr == FLASH_WRITE_PORT_ADDR)
    {
        for(int i=0;i<5;i++)
        {
            uint32_t temp = (uint32_t)ctx_register[2061+i*3]*0x10000 + ctx_register[2060+i*3];
            FLASH_ProgramWord(addr + 8*i, temp);  //0x004E0096
            FLASH_ProgramWord(addr + 8*i + 4, (uint32_t)ctx_register[2062+i*3]);
            rt_kprintf("%d:%d %d\r\n", i, temp, (uint32_t)ctx_register[2062+i*3]);
        }
    }

    FLASH_Lock();
}

/**
 * @brief  Main program.
 */
void my_pvd_init(void)
{
    GPIO_InitType GPIO_InitStructure;
    GPIO_InitStruct(&GPIO_InitStructure);
    /* Enable LED Port Clock */
    RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOA, ENABLE);
    /* Configure the GPIO_LED pin */
    GPIO_InitStructure.Pin        = GPIO_PIN_8;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;
    GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);

    GPIOA->PBC = GPIO_PIN_8;

    /* Enable PWR and BKP clock */
    RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPH_PWR | RCC_APB1_PERIPH_BKP, ENABLE);
    /* Configure EXTI Line to generate an interrupt on falling edge */
    EXTI_Configuration();
    /* NVIC configuration */
    NVIC_Configuration();
    /* Configure the PVD Level to 2.9V */
    PWR_PvdRangeConfig(PWR_PVDRANGRE_2V9);
    /* Enable the PVD Output */
    PWR_PvdEnable(ENABLE);
}

/**
 * @brief  This function handles the PVD Output interrupt request defined in main.h .
 */

void PVD_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    if (EXTI_GetITStatus(EXTI_LINE16) != RESET)
    {
        /* Toggle LED1 */

        GPIOA->PBSC = GPIO_PIN_8;
        write_params_flash(FLASH_WRITE_CMD_ADDR);
        write_params_flash(FLASH_WRITE_PORT_ADDR);
        GPIOA->PBC = GPIO_PIN_8;

        /* Clear the Key Button EXTI line pending bit */
        EXTI_ClrITPendBit(EXTI_LINE16);
    }

    /* leave interrupt */
    rt_interrupt_leave();
}
